﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using AWS.SLAM.Configuration;
using AWS.SLAM.Data;
using AWS.SLAM.Events;
using AWS.SLAM.Hierarchy.Data;
using AWS.SLAM.Logging;
using Microsoft.SharePoint;

namespace AWS.SLAM.Hierarchy
{
    /// <summary>
    /// HierarchicalListItemUpdater updates an item to SLAM's datasource(s) when a List Item is
    /// updated in a List configured to be managed by SLAM in SharePoint then updates its 
    /// position in the hierarchy of items also managed by SLAM.  
    /// 
    /// A List in SharePoint configured to use the HierarchicalListItemUpdater requires that it contain
    /// a field of type HierarchyPositionField.
    /// </summary>
    public class HierarchicalListItemUpdater : ListItemUpdater
    {
        #region Private State

        /// <summary>
        /// SLAM Data service layer
        /// </summary>
        private IDataServices _dataServices;

        /// <summary>
        /// SLAM Configuration
        /// </summary>
        private IConfigurationManager _configuration;

        /// <summary>
        /// SLAM Logger
        /// </summary>
        private ILogger _logger;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates instance of HierarchicalListItemUpdater for the given 
        /// DataServices, Configuration, and Logger.
        /// </summary>
        /// <param name="dataServices"></param>
        /// <param name="configuration"></param>
        /// <param name="logger"></param>
        public HierarchicalListItemUpdater(IDataServices dataServices, IConfigurationManager configuration, ILogger logger)
            : base(dataServices, configuration, logger)
        {
            _dataServices = dataServices;
            _configuration = configuration;
            _logger = logger;
        }

        #endregion

        /// <summary>
        /// Updates an item in SLAM's external datasource then uses the value of the HierarchyPositionField
        /// that must be present in the given listItem to insert into or move the item in the hierarchy
        /// managed by SLAM for the List Item's Parent List.
        /// </summary>
        /// <param name="listItem"></param>
        /// <returns></returns>
        public override bool Update(SPListItem listItem)
        {
            //Execute default SLAM Update process for a configured List
            bool updateResult = base.Update(listItem);

            //Open Hierarchy's DataService with the Default ConnectionString and DataSchema.
            //This process assumes the Hierarchy is saved in a SQL Server database and is using
            //a SLAM XML Configuration file.
            DataService dataService = new DataService(_configuration.GetSection<ConnectionStringSection>("ConnectionStrings").Default,
                ((XmlSqlDataMapping)_configuration.DataMapping).GetDataSchema());

            //Check configuration for the presence of a TableName for the listItem's
            //Parent List's ID and Title.  If it is present, use it as the item's typeName instead of the
            //Parent List's Title.  Otherwise if it is not present use the Parent List's Title
            string itemTypeName = _configuration.DataMapping.GetTypeAttribute(listItem.ParentList.ID.ToString(), listItem.ParentList.Title, "TableName");
            if (String.IsNullOrEmpty(itemTypeName))
            {
                itemTypeName = listItem.ParentList.Title;
            }

            //For this type, add the Hierarchy "Left", "Right", and "Hierarchy Level" columns
            //in the SLAM table if they do not exist.
            dataService.AddHierarchyColumns(itemTypeName);

            //Get the Hierarchy Position Field's value from the listItem regardless of its name
            string hierarchyPositionFieldValue = listItem.GetHierarchyPositionFieldValue();

            if (!String.IsNullOrEmpty(hierarchyPositionFieldValue))
            {
                //The Hierarchy Position Field's value has at least 2 parts, the first
                //part contains a Parent GUID Id, the second part contains a sibling
                //ListItem GUID Id. 
                string[] fieldValueParts = hierarchyPositionFieldValue.Split('|');
                if (fieldValueParts.Length > 2 && !String.IsNullOrEmpty(fieldValueParts[0]))
                {
                    if (fieldValueParts[2] == "a")
                    {
                        //If the first part is an Empty Guid then this listItem is a root node. Otherwise
                        //add as a child node
                        if (fieldValueParts[0] != Guid.Empty.ToString())
                        {
                            //If the second part is an Empty Guid then this listItem goes at the end
                            //of the parent's children, otherwise it goes to the left, in place, of the
                            //sibling defined by fieldValuesParts[1]
                            if (!String.IsNullOrEmpty(fieldValueParts[1]) && fieldValueParts[1] != Guid.Empty.ToString())
                            {
                                dataService.AddAsLeftSiblingNode(itemTypeName, fieldValueParts[1], listItem.UniqueId.ToString());
                            }
                            else
                            {
                                dataService.AddAsLastChildNode(itemTypeName, fieldValueParts[0], listItem.UniqueId.ToString());
                            }
                        }
                        else
                        {
                            dataService.AddAsRootNode(itemTypeName, listItem.UniqueId.ToString());
                        }
                    }
                    else if (fieldValueParts[2] == "m")
                    {
                        //If the first part is an Empty Guid then this listItem should become a root node. 
                        //Otherwise it should become a child node
                        if (fieldValueParts[0] != Guid.Empty.ToString())
                        {
                            //If the second part is an Empty Guid then this listItem goes at the end
                            //of the parent's children, otherwise it goes to the left, in place, of the
                            //sibling defined by fieldValuesParts[1]
                            if (!String.IsNullOrEmpty(fieldValueParts[1]) && fieldValueParts[1] != Guid.Empty.ToString())
                            {
                                if (dataService.MoveToLeftSiblingNode(itemTypeName, fieldValueParts[1], listItem.UniqueId.ToString()) < 1)
                                {
                                    dataService.AddAsLeftSiblingNode(itemTypeName, fieldValueParts[1], listItem.UniqueId.ToString());
                                }
                            }
                            else if(dataService.MoveToLastChildNode(itemTypeName, fieldValueParts[0], listItem.UniqueId.ToString()) < 1)
                            {
                                dataService.AddAsLastChildNode(itemTypeName, fieldValueParts[0], listItem.UniqueId.ToString());
                            }
                        }
                        else
                        {
                            if (dataService.MoveToRootNode(itemTypeName, listItem.UniqueId.ToString()) < 1)
                            {
                                dataService.AddAsRootNode(itemTypeName, listItem.UniqueId.ToString());
                            }
                        }
                    }

                    dataService.RecalculateHierarchyLevels(itemTypeName);
                }
            }
            return updateResult;
        }
    }
}
